package com.project.quiktask.controller;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Date;
import java.sql.Time;
import java.text.ParseException;
import java.util.Vector;

import com.project.quiktask.Task;
import com.project.quiktask.datastore.FileLoader;
import com.project.quiktask.datastore.FileStorer;
import com.project.quiktask.exception.StartDateAfterEndDateException;
import com.project.quiktask.exception.StartTimeAfterEndTimeException;
import com.project.quiktask.parser.Parser;
import com.project.quiktask.util.Result;
import com.project.quiktask.util.Variable;

/**
 * This class handles the updation of tasks existing the QuikTask Manager.
 * It supports deletion by: ID displayed of the task
 * 							Keyword in the task
 * 
 * @author M I Azima
 *
 */
public class UpdateHandler implements CommandHandler {
	Result feedback;
	Task originalTask;
	Task newTask = new Task();
	public Task updatedTask = new Task();
	public Task taskToBeUpdated = new Task();
	Vector<Task> taskContainer = new Vector<Task>();

	public static final int ONE_TASK = 1;
	public static final int UPDATE_KEYWORDS = 0;

	public UpdateHandler() {
		
	}

	public Result execute(String parameter) {
		Result loadFileResult = loadStorageFile();

		if (isFileLoadedSuccessfully(loadFileResult)) {
			Result feedbackResult = executeUpdateCommand(parameter);
			return feedbackResult;
		} else
			return loadFileResult;
	}

	@SuppressWarnings("finally")
	public Result loadStorageFile()	{
		try	{
			FileLoader loader = new FileLoader(Variable.STORAGE_FILE_NAME);
			taskContainer = loader.load();
		} catch (FileNotFoundException e) {
			return new Result(Variable.FEEDBACK_ERROR_FILE_NOT_FOUND);
		} catch (IOException e) {
			return new Result(Variable.FEEDBACK_ERROR_GENERAL);
		} catch (ParseException e) {
			return new Result(Variable.FEEDBACK_ERROR_GENERAL);
		} finally {
			return new Result(Variable.FEEDBACK_SUCCESS_FILE_LOADED);
		}
	}

	public boolean isFileLoadedSuccessfully(Result result) {
		if (result.getFeedback() == Variable.FEEDBACK_SUCCESS_FILE_LOADED)
			return true;
		else
			return false;
	}

	public Result executeUpdateCommand(String parameter)	{
		Vector<Task> updatedTasks = searchForTasks(parameter);
		if (!executeSearchResults(updatedTasks)) {
			return feedback;
		} else {
			updateTask(parameter);
			updateTaskContainer();
			storeUpdatedTaskContainer();
			return feedback;
		}
	}

	public Vector<Task> searchForTasks(String parameter) {
		SearchHandler Search = new SearchHandler();
		Vector<Task> updatedTasks = null;

		String keyword = parseKeyword(parameter);
		updatedTasks = Search.searchByKeyword(keyword, taskContainer);
		return updatedTasks;
	}

	public String parseKeyword(String parameter)	{
		String[] fields = Parser.parseString(parameter);
		String keyword = fields[UPDATE_KEYWORDS];
		return keyword;
	}

	public boolean executeSearchResults(Vector<Task> updatedTasks) {
		if (updatedTasks.size() > ONE_TASK) {
			feedback = new Result(Variable.FEEDBACK_MANY_TASKS_WITH_SAME_KEYWORD, updatedTasks);
			return false;
		} else if (updatedTasks.size() == ONE_TASK) {
			taskToBeUpdated = updatedTasks.get(0);
			originalTask = new Task(taskToBeUpdated);
			return true;
		} else	{
			feedback = new Result(Variable.FEEDBACK_NO_MATCHING_RESULTS);
			return false;
		}
	}

	public Task findTaskToBeUpdated(Vector<Task> updatedTasks) {
		for(Task taskToBeUpdated:updatedTasks)
			for(Task task:taskContainer)
				if(taskToBeUpdated.equals(task))
					return task;
		return null;
	}

	public void updateTask(String parameter) {

		try {
			String[] updateParameter = parseUpdateParameters(parameter);
			newTask = TaskParser.getTaskFromString(updateParameter);
			updatedTask = updateParameters(taskToBeUpdated);
			feedback = new Result(Variable.FEEDBACK_UPDATE_SUCCESSFUL);
		} catch (ParseException e) {
			feedback = new Result(Variable.FEEDBACK_ERROR_GENERAL);
		} catch (StartDateAfterEndDateException e) {
			feedback=new Result(e.getMessage());
		} catch (StartTimeAfterEndTimeException e) {
			feedback=new Result(e.getMessage());
		}
	}

	public String[] parseUpdateParameters(String parameter) {
		String[] fields = Parser.parseString(parameter);
		String[] updateParameter = new String[fields.length-1];

		for (int i = 1; i < fields.length; i++)
			updateParameter[i-1] = fields[i];
		return updateParameter;
	}

	/**
	 * Updates the following parameters of the task:
	 * 
	 * startDate;
	 * endDate;
	 * deadlineDate;
	 * startTime;
	 * endTime;
	 * deadlineTime;
	 * importance;
	 * 
	 * @param taskToBeUpdated
	 */
	private Task updateParameters(Task updateTask)	{
		String updatedTaskDescription;
		Date updatedStartDate;
		Date updatedEndDate;
		Date updatedDeadlineDate;
		Time updatedStartTime;
		Time updatedEndTime;
		Time updatedDeadlineTime;
		boolean updatedImportance;

		if(newTask.getTaskDescription() != null)	{
			updatedTaskDescription = newTask.getTaskDescription();
			updateTask.setTaskDescription(updatedTaskDescription);
		}
		if(newTask.getEndDate() != null)	{
			updatedEndDate = newTask.getEndDate();
			updateTask.setEndDate(updatedEndDate);
		}
		if(newTask.getStartDate() != null)	{
			updatedStartDate = newTask.getStartDate();
			updateTask.setStartDate(updatedStartDate);
		}
		if(newTask.getDeadlineDate() != null)	{
			updatedDeadlineDate = newTask.getDeadlineDate();
			updateTask.setDeadlineDate(updatedDeadlineDate);
		}		
		if(newTask.getStartTime() != null)	{
			updatedStartTime = newTask.getStartTime();
			updateTask.setStartTime(updatedStartTime);
		}		
		if(newTask.getEndTime() != null)	{
			updatedEndTime = newTask.getEndTime();
			updateTask.setEndTime(updatedEndTime);
		}
		if(newTask.getDeadlineTime() != null)	{
			updatedDeadlineTime = newTask.getDeadlineTime();
			updateTask.setDeadlineTime(updatedDeadlineTime);
		}
		if(newTask.getImportance() != updateTask.getImportance())	{
			updatedImportance = newTask.getImportance();
			updateTask.setImportance(updatedImportance);
		}
		return updateTask;
	}

	public void updateTaskContainer()	{
		taskContainer.remove(updatedTask);
		taskContainer.add(taskToBeUpdated);
	}

	public void storeUpdatedTaskContainer()	{
		FileStorer storer = new FileStorer();
		try {
			storer.storeManyTask(taskContainer);
		} catch (IOException e) {
			e.printStackTrace();
			feedback = new Result(Variable.FEEDBACK_ERROR_GENERAL);
		}
	}

	public Result undo()	{
		try {
			DeleteHandler.deleteOneTask(taskToBeUpdated);
			AddHandler.addOneTask(originalTask);
		} catch (IOException e) {
			e.printStackTrace();
			return new Result(Variable.FEEDBACK_ERROR_GENERAL);
		} catch (ParseException e) {
			e.printStackTrace();
			return new Result(Variable.FEEDBACK_COMMAND_INVALID);
		}

		return new Result(Variable.FEEDBACK_UNDO_SUCESSFUL);
	}

}
